package com.boot.schedule;

import com.boot.core.exception.UnsupportedClassException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @description 调度任务管理器
 * @date 2019/12/30 14:59
 **/
@Slf4j
public class ScheduledManager implements ApplicationListener<TaskEvent> {

    private final ThreadPoolTaskScheduler scheduler;

    private final Map<String, ScheduledFuture<?>> scheduleMap;

    public ScheduledManager(ThreadPoolTaskScheduler scheduler) {
        this.scheduler = scheduler;
        scheduleMap = new ConcurrentHashMap<>();
    }

    public void start(AbstractScheduleTask task) throws Exception {
        ScheduledFuture<?> future = scheduler.schedule(task, task.getCronTrigger());
        if (scheduleMap.containsKey(task.getId())) {
            throw new Exception("任务id重复");
        } else {
            scheduleMap.put(task.getId(), future);
        }
    }

    public void start(String id, Runnable task, CronTrigger trigger) throws Exception {
        ScheduledFuture<?> future = scheduler.schedule(task, trigger);
        if (scheduleMap.containsKey(id)) {
            throw new Exception("任务id重复");
        } else {
            scheduleMap.put(id, future);
        }
    }

    public void stop(String id) {
        ScheduledFuture<?> future = scheduleMap.get(id);
        if (future != null) {
            future.cancel(true);
            scheduleMap.remove(id);
        }
    }

    @SneakyThrows
    @Override
    public void onApplicationEvent(TaskEvent event) {
        if (event.getSource() instanceof AbstractScheduleTask) {
            AbstractScheduleTask task = (AbstractScheduleTask) event.getSource();
            if (TaskEvent.START == event.getSignal()) {
                this.start(task);
            } else if (TaskEvent.STOP == event.getSignal()) {
                this.stop(task.getId());
                task.afterStop();
            }
        } else {
            throw new UnsupportedClassException(this.getClass(), event.getSource().getClass());
        }

    }
}
